前端灰度发布与可监控、可回滚策略相结合,形成了一个强大的系统稳定性保障机制。通过这三个策略的协同工作,可以确保前端应用在不断迭代和更新的同时,保持高性能和高稳定性,本文介绍如何通过配置MSE云原生网关实现前端灰度。
端到端全链路灰度实现
在微服务场景中,应用间的调用是随机的。当您部署的Spring Cloud应用或Dubbo应用存在升级版本时,可能会导致无法将具有一定特征的流量路由到应用的目标版本。通过MSE提供的云原生网关实现全链路灰度,配合前端灰度方案,即可实现端到端的全链路灰度。
前端用户每一次的请求都经过云原生网关,经过权限系统验证后,所有请求的Cookie中都带上了用户的唯一标识,比如 userid: 001
。
网关挂载了一个 frontend-gray
插件,通过配置插件规则,将灰度流量进行映射并传递。
前提条件
已下载frontend-gray,源代码请参见GitHub。
Ingress类型服务实现前端灰度
通过MSE Ingress访问容器服务,请参见MSE Ingress访问容器服务。
步骤1:使用容器服务部署应用
应用部署的具体操作,请参见创建无状态工作负载Deployment。
frontend-base.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- image: 'registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/user-gray:base'
imagePullPolicy: Always
name: frontend
resources: {}
---
apiVersion: v1
kind: Service
metadata:
name: frontend-base-svc
namespace: default
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: frontend
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
labels:
ingress-controller: mse
namespace: default
name: frontend-base-ingress
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: frontend-base-svc
port:
number: 80
path: /
pathType: Prefix
frontend-gray.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-gray
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: frontend-gray
template:
metadata:
labels:
app: frontend-gray
spec:
containers:
- image: 'registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/user-gray:gray'
imagePullPolicy: Always
name: frontend-gray
resources: {}
---
apiVersion: v1
kind: Service
metadata:
name: frontend-gray-svc
namespace: default
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: frontend-gray
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
labels:
ingress-controller: mse
annotations:
nginx.ingress.kubernetes.io/canary: 'true'
nginx.ingress.kubernetes.io/canary-by-header: x-higress-tag
nginx.ingress.kubernetes.io/canary-by-header-value: gray
name: frontend-gray-ingress
namespace: default
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: frontend-gray-svc
port:
number: 80
path: /
pathType: Prefix
步骤2:MSE控制台配置灰度插件
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。
在左侧导航栏,单击插件市场。
在插件市场页面,选择自定义,然后单击创建插件。
在创建插件面板,填写插件参数信息,单击确定,等待插件发布成功。
参数
值
插件名称
frontend-gray
插件描述
frontend-gray
wasm实现语言
TinyGo
wasm文件
上传下载的 frontend-gray(
main.wasm
)文件插件执行阶段
默认阶段
插件执行优先级
100
插件发布成功之后,单击创建的插件
frontend-gray
选项卡,选择插件配置 > 实例级插件规则。在实例级插件规则页面配置如下规则,详细配置可参见配置规则。
grayKey: userid rules: - name: beta-user grayKeyValue: - "00000002" - "00000003" baseDeployment: version: base grayDeployments: - name: beta-user version: gray enabled: true
步骤3:结果验证
登录容器服务控制台,在左侧导航栏选择集群,在集群列表页面单击所创建的容器服务集群,进入集群详情页,在左侧导航栏选择网络 > 路由,查看公网访问端点。
访问公网端点
8.136.xxx.xxx
,登录admin/ice
账号,访问主版本,用户ID为 00000001。访问公网端点
8.136.xxx.xxx
,登录普通用户user/ice
,访问灰度版本,用户ID为 00000002。
ACK容器服务实现前端灰度
步骤1:使用容器服务部署应用
应用部署的具体操作,请参见创建无状态工作负载Deployment。
frontend-base.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- image: 'registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/user-gray:base'
imagePullPolicy: Always
name: frontend
resources: {}
---
apiVersion: v1
kind: Service
metadata:
name: frontend-base-svc
namespace: default
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: frontend
type: ClusterIP
frontend-gray.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-gray
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: frontend-gray
template:
metadata:
labels:
app: frontend-gray
spec:
containers:
- image: 'registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/user-gray:gray'
imagePullPolicy: Always
name: frontend-gray
resources: {}
---
apiVersion: v1
kind: Service
metadata:
name: frontend-gray-svc
namespace: default
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: frontend-gray
type: ClusterIP
为ACK命名空间中的应用开启MSE微服务治理
登录MSE治理中心控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择治理中心 > 应用治理。
在应用列表页面,单击ACK应用接入。
在ACK应用接入对话框中,进行配置,配置完成后,单击确定。
配置项
说明
集群类型
选择ACK集群、ACK Serverless集群或ACS集群。
说明如果您尚未授权容器服务调用微服务引擎,则需要单击请授权进行授权。
集群名称/ID
选择接入MSE微服务治理的集群名称/ID,可通过关键词搜索。
ack-onepilot
显示ack-onepilot接入状态。
如果您未安装ack-onepilot,单击ack-onepilot右侧的点击安装,安装完成后状态会显示为已安装。
如果您使用子账号接入,提示没有权限使用时,您可以登录容器服务管理控制台进入目标集群,然后单击运维管理>组件管理,找到ack-onepilot,点击安装。
说明该步骤接入的组件为ack-onepilot,您可以登录容器服务管理控制台进入目标集群,然后单击运维管理>组件管理查看详情。
ack-onepilot安装后会自动注入探针,可能会导致应用启动耗时增加(10s内)。
接入类型
选择命名空间接入。
容器集群命名空间
选择容器集群命名空间。
治理命名空间
选择治理命名空间。在对应命名空间下重新部署现有应用或新创建的应用,均会接入到MSE微服务治理中。关于命名空间的相关信息,请参见微服务命名空间管理。
为单个应用开启MSE微服务治理
登录MSE治理中心控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择治理中心 > 应用治理。
在应用列表页面,单击ACK应用接入。
在ACK应用接入对话框中,进行配置,配置完成后,单击确定。
配置项
说明
集群类型
选择ACK集群、ACK Serverless集群或ACS集群。
说明如果您尚未授权容器服务调用微服务引擎,则需要单击请授权进行授权。
集群名称/ID
选择接入MSE微服务治理的集群名称/ID,可通过关键词搜索。
ack-onepilot
显示ack-onepilot接入状态。
如果您未安装ack-onepilot,单击ack-onepilot右侧的点击安装,安装完成后状态会显示为已安装。
如果您使用子账号接入,提示没有权限使用时,您可以登录容器服务管理控制台进入目标集群,然后单击运维管理>组件管理,找到ack-onepilot,点击安装。
说明该步骤接入的组件为ack-onepilot,您可以登录容器服务管理控制台进入目标集群,然后单击运维管理>组件管理查看详情。
ack-onepilot安装后会自动注入探针,可能会导致应用启动耗时增加(10s内)。
接入类型
选择单个应用接入。
接入步骤
按照接入步骤进行操作。
Step 1:进入集群工作负载-无状态应用页面,切换到应用的命名空间下。
Step 2:找到所接入的应用,点击「查看Yaml」。
Step 3:按以下格式编辑Labels,完成后点击「更新」。
spec: template: metadata: labels: # 填写“on”表示开启接入,需加上双引号 msePilotAutoEnable: "on" # 填写接入到的治理命名空间,值不存在可自动新建 mseNamespace: 202401 # 填写接入MSE的实际应用名称,需加上双引号 msePilotCreateAppName: "your-deployment-name"
步骤2:MSE控制台配置灰度插件
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。
在左侧导航栏,单击插件市场。
在插件市场页面,选择自定义,然后单击创建插件。
在创建插件面板,填写插件参数信息,单击确定,等待插件发布成功。
参数
值
插件名称
frontend-gray
插件描述
frontend-gray
wasm实现语言
TinyGo
wasm文件
上传下载的 frontend-gray(
main.wasm
)文件插件执行阶段
默认阶段
插件执行优先级
100
插件发布成功之后,单击创建的插件
frontend-gray
选项卡,选择插件配置 > 实例级插件规则。在实例级插件规则页面配置如下规则,详细配置可参见配置规则。
grayKey: userid rules: - name: beta-user grayKeyValue: - "00000002" - "00000003" baseDeployment: version: base grayDeployments: - name: beta-user version: gray enabled: true
步骤3:添加网关服务来源
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。
在左侧导航栏,选择路由管理,然后选择来源页签。
单击创建来源。在创建来源面板,配置来源类型为容器服务,ACK/ACK Serverless集群选择所创建的容器服务集群, 然后单击确定。
步骤4:创建服务
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏选择云原生网关 > 网关列表。
在网关列表页面,单击目标网关名称。
在左侧导航栏,选择路由管理,然后选择服务页签。
单击创建服务。在创建服务面板,配置服务相关参数,然后单击确定。
步骤5:创建base路由
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。
在左侧导航栏,单击路由管理,然后在路由页签单击创建路由。
在创建路由页面,配置相关项,然后单击保存。
步骤6:创建gray路由
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。
在左侧导航栏,单击路由管理,然后在路由页签单击创建路由。
在创建路由页面,配置相关配置项,然后单击保存。
说明gray
代表灰度版本,和frontend-gray
配置中deploy.gray.version
对应
步骤7:结果验证
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。
在网关详情页面找到网关入口,查看公网访问端点。
访问公网端点
8.136.xxx.xxx
,登录admin/ice
账号,访问主版本,用户ID为 00000001。访问公网端点
8.136.xxx.xxx
,登录普通用户user/ice
,访问灰度版本,用户ID为 00000002。
ECS类型服务实现前端灰度
步骤1:ECS分别部署两个前端应用
基线应用地址为:120.79.137.243:80
灰度应用地址为:120.79.137.243:8081
步骤2:创建服务
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏选择云原生网关 > 网关列表。
在网关列表页面,单击目标网关名称。
在左侧导航栏,选择路由管理,然后选择服务页签。
单击创建服务。在创建服务面板,服务来源为固定地址,配置服务相关参数,然后单击确定。
步骤3:创建base路由
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。
在左侧导航栏,单击路由管理,然后在路由页签单击创建路由。
在创建路由页面,配置相关配置项,然后单击保存。
步骤4:创建gray路由
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。
在左侧导航栏,单击路由管理,然后在路由页签单击创建路由。
在创建路由页面,配置相关项,然后单击保存。
说明gray
代表灰度版本,和frontend-gray
配置中deploy.gray.version
对应
步骤5:MSE控制台配置灰度插件
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。
在左侧导航栏,单击插件市场。
在插件市场页面,选择自定义,然后单击创建插件。
在创建插件面板,填写插件参数信息,单击确定,等待插件发布成功。
参数
值
插件名称
frontend-gray
插件描述
frontend-gray
wasm实现语言
TinyGo
wasm文件
上传下载的 frontend-gray(
main.wasm
)文件插件执行阶段
默认阶段
插件执行优先级
100
插件发布成功之后,单击创建的插件
frontend-gray
选项卡,选择插件配置 > 实例级插件规则。在实例级插件规则页面配置如下规则,详细配置可参见配置规则。
grayKey: userid rules: - name: beta-user grayKeyValue: - "00000002" - "00000003" baseDeployment: version: base grayDeployments: - name: beta-user version: gray enabled: true
步骤6:结果验证
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。
在网关详情页面找到网关入口,查看公网访问端点。
访问公网端点
8.136.xxx.xxx
,登录admin/ice
账号,访问主版本,用户ID为 00000001。访问公网端点
8.136.xxx.xxx
,登录普通用户user/ice
,访问灰度版本,用户ID为 00000002。
CDN/OSS类型服务实现前端灰度
步骤1:OSS文件规划
- app1 # 应用
- dev # dev版本
- index.html
- js
...
- css
...
- images
...
- 0.0.1 # 001版本
- index.html
- js
...
- css
...
- images
...
- 0.0.2 # 002版本
- index.html
- js
...
- css
...
- images
...
- app2
- dev
- index.html
- js
...
- css
...
- images
...
- 0.0.1
- index.html
- js
...
- css
...
- images
...
- 0.0.2
- index.html
- js
...
- css
...
- images
...
步骤2:创建服务
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏选择云原生网关 > 网关列表。
在网关列表页面,单击目标网关名称。
在左侧导航栏,选择路由管理,然后选择服务页签。
单击创建服务。在创建服务面板,服务来源为DNS域名,域名列表填写OSS地址,然后单击确定。
重要如果OSS的和网关在同一个Region,建议填写OSS的内网地址,如果不在一个Region,请填写公网地址。
步骤3:创建路由
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。
在左侧导航栏,单击路由管理,然后在路由页签单击创建路由。
在创建路由页面,配置相关项,然后单击保存。
步骤4:MSE控制台配置灰度插件
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。
在左侧导航栏,单击插件市场。
在插件市场页面,选择自定义,然后单击创建插件。
在创建插件面板,填写插件参数信息,单击确定,等待插件发布成功。
参数
值
插件名称
frontend-gray
插件描述
frontend-gray
wasm实现语言
TinyGo
wasm文件
上传下载的 frontend-gray(
main.wasm
)文件插件执行阶段
默认阶段
插件执行优先级
100
插件发布成功之后,单击创建的插件
frontend-gray
选项卡,选择插件配置 > 实例级插件规则。在实例级插件规则页面配置如下规则,详细配置可参见配置规则。
grayKey: userid rules: - name: beta-user grayKeyValue: - "00000002" - "00000003" rewrite: host: xx.oss-cn-shanghai.aliyuncs.com ##OSS 地址 indexRouting: "/app1": "/project-a/app1/{version}/index.html" #首页(html)路径重写 fileRouting: "/app1": "/project-a/app1/{version}" #资源(css/js/images)路径重写 baseDeployment: version: dev grayDeployments: - name: beta-user version: 0.0.1 enabled: true
步骤5:结果验证
登录MSE网关管理控制台,并在顶部菜单栏选择地域。
在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。
在网关详情页面找到网关入口,查看公网访问端点。
访问公网端点
8.136.xxx.xxx
,登录admin/ice
账号,访问主版本,用户ID为 00000001。访问公网端点
8.136.xxx.xxx
,登录普通用户user/ice
,访问灰度版本,用户ID为 00000002。
FAQ
前端灰度是否还可以配置重写策略
如果服务来源是非CDN/OSS ,可以搭配重写策略生效。
如果服务来源是CDN/OSS的前端灰度是不可以搭配重写策略,因为相关的重写策略在frontend-gray灰度插件中实现了,如果配置重写策略,会发生冲突,返回403等一些异常情况。
是否可以往HTML首页注入一些全局变量
可以在html的<head> 标签中(一般是CSS样式等属性),或者<body>标签的头部和尾部注入一些全局JavaScript脚本。
通过injection往HTML首页注入代码,可以在head标签注入代码,也可以在body标签的first和last位置注入代码。
grayKey: userid
rules:
- name: inner-user
grayKeyValue:
- '00000001'
- '00000005'
baseDeployment:
version: base
grayDeployments:
- name: beta-user
version: gray
enabled: true
weight: 80
injection:
head:
- <script>console.log('Header')</script>
body:
first:
- <script>console.log('hello world before')</script>
- <script>console.log('hello world before1')</script>
last:
- <script>console.log('hello world after')</script>
- <script>console.log('hello world after2')</script>
灰度版本生效时机?
假设A用户现在的前端版本是0.0.1
, 这时候发布前端版本 0.0.2
, 并且A客户命中了灰度规则,是否能立即生效?
是不会立即生效,出于下面几点原因考虑:
如果发布版本需要实时生效,这时候就需要由后端来动态控制版本。首先无法实现前后端发布解耦,其次页面的稳定性强依赖这个接口,无法做CDN加速。
假设版本能够实时生效,客户在使用某个功能的时候,可能出现上一秒还在使用某个按钮,下一秒这个按钮就不见了的情况。体验非常糟糕。
什么时机刷新页面?
一般网站是有设置Session超时重新登录,一段时间没有访问后,需重新登录页面。
用户通过登录页面登录到应用中。
所以,在登录页面的时候,需要刷新页面,以获取最新的灰度信息。前端登录示例代码如下:
async function handleLogin(values: LoginParams) {
try {
const result = await login(values);
if (result.success) {
message.success('登录成功!');
await updateUserInfo();
const urlParams = new URL(window.location.href).searchParams;
window.location.href = `${urlParams.get('redirect') || '/'}`;
return;
}
console.log(result);
// 如果失败去设置用户错误信息,显示提示信息
setLoginResult(result);
} catch (error) {
message.error('登录失败,请重试!');
console.log(error);
}
}